package com.xtck.ha.common.core.web.service.dsimpl;

import com.alibaba.fastjson.serializer.SerializeFilter;
import com.alibaba.fastjson.serializer.ValueFilter;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import com.github.pagehelper.Page;
import com.xtck.ha.common.core.annotation.ClassKey;
import com.xtck.ha.common.core.annotation.DbAnnotion;
import com.xtck.ha.common.core.annotation.SortKey;
import com.xtck.ha.common.core.config.DsServerConfig;
import com.xtck.ha.common.core.constant.HttpStatus;
import com.xtck.ha.common.core.domain.R;
import com.xtck.ha.common.core.utils.DomainUtils;
import com.xtck.ha.common.core.utils.PageUtils;
import com.xtck.ha.common.core.utils.reflect.ReflectUtils;
import com.xtck.ha.common.core.web.page.TableDataInfo;
import com.xtck.ha.common.core.web.service.IBaseService;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.*;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.util.UriComponentsBuilder;

import java.lang.reflect.Field;
import java.net.URI;
import java.util.*;
import java.util.stream.Collectors;

@Slf4j
@Service
@Data
public class BaseServiceImpl<T> implements IBaseService<T> {

    protected Class<T> entityClass = this.currentModelClass();

    @Autowired
    private DsServerConfig dsServerConfig;

    public Class<T> getEntityClass() {
        return this.entityClass;
    }

    public T getTinstance(){
        try {
            return this.getEntityClass().getDeclaredConstructor().newInstance();
        } catch (Exception e) {
            return null;
        }
    }

    public String getDatasourceFlag(Object obj) {
        JSONObject jo = new JSONObject();
        Class<?> clazz = obj.getClass();
        String Dbflag;
        // 检查类是否被@MyAnnotation注解
        if (clazz.isAnnotationPresent(DbAnnotion.class)) {
            // 获取类上的@MyAnnotation注解
            DbAnnotion annotation = clazz.getAnnotation(DbAnnotion.class);

            // 获取注解的属性值
            Dbflag = annotation.value();
        } else {
            Dbflag = "master";
        }
        return Dbflag;
    }

    protected Class<T> currentModelClass() {
        return ReflectUtils.getClassGenricType(this.getClass(),0);
    }

    protected String getDsRouteKey(){
        return dsServerConfig.getUseDb(DomainUtils.getDomainTableName(this.getTinstance()));
    }

    protected String geturl(){
        return dsServerConfig.getUrlWithTableAndFlag(DomainUtils.getDomainTableName(this.getTinstance()),getDatasourceFlag(this));
    }

    protected String getTableUrl(){
        return dsServerConfig.getUrlOnly(DomainUtils.getDomainTableName(this.getTinstance()));
    }

    @Override
    public T selectTById(Long id) {
        RestTemplate restTemplate = new RestTemplate();
        UriComponentsBuilder ucb = UriComponentsBuilder.fromHttpUrl(geturl()+"/"+id);
        ucb = ucb.queryParam("pk", getClassKey());
        URI uri = ucb.build().toUri();
        // 设置请求头，特别是Authorization头部来携带token
        HttpHeaders headers = new HttpHeaders();
        headers.add("Ds-Route-key", this.getDsRouteKey());
        // 不需要传递body对于GET请求来说，除非你需要传递JSON等格式的参数体，但通常不这么做。
        HttpEntity<String> httpEntity = new HttpEntity<>(headers);
        // 执行GET请求并处理响应
        R result = restTemplate.exchange(uri, HttpMethod.GET, httpEntity, R.class).getBody();
        T entity = this.getTinstance();
        if (R.isSuccess(result)) {
            entity = JSONObject.parseObject(JSONObject.toJSONString(result.getData()),this.getEntityClass());
        }
        return entity;
    }

    @Override
    public T selectTById(String id) {
        RestTemplate restTemplate = new RestTemplate();
        UriComponentsBuilder ucb = UriComponentsBuilder.fromHttpUrl(geturl()+"/"+id);
        ucb = ucb.queryParam("pk", getClassKey());
        URI uri = ucb.build().toUri();
        // 设置请求头，特别是Authorization头部来携带token
        HttpHeaders headers = new HttpHeaders();
        headers.add("Ds-Route-key", this.getDsRouteKey());
        // 不需要传递body对于GET请求来说，除非你需要传递JSON等格式的参数体，但通常不这么做。
        HttpEntity<String> httpEntity = new HttpEntity<>(headers);
        // 执行GET请求并处理响应
        R result = restTemplate.exchange(uri, HttpMethod.GET, httpEntity, R.class).getBody();
        T entity = this.getTinstance();
        if (R.isSuccess(result)) {
            entity = JSONObject.parseObject(JSONObject.toJSONString(result.getData()),this.getEntityClass());
        }
        return entity;
    }

    @Override
    public List<T> selectTList(T t) {
        Page page = PageUtils.getLocalPage();

        RestTemplate restTemplate = new RestTemplate();
        Map<String, Object> map = DomainUtils.objectToMapForQuery(t);
        JSONObject jo = new JSONObject();
        if (!map.isEmpty()){
            if (map.size()>1){
                List list = new ArrayList();
                map.forEach((k,v)->{
                    JSONObject pa = new JSONObject();
                    pa.put(k,v);
                    list.add(pa);
                });
                jo.put("$and",list);
            }else {
                jo.putAll(map);
            }
        }
        UriComponentsBuilder ucb = UriComponentsBuilder.fromHttpUrl(geturl());
        if(!map.isEmpty()){
            ucb = ucb.queryParam("filter", jo.toJSONString());
        }
        if (page!=null){
            ucb = ucb.queryParam("page",page.getPageNum())
                    .queryParam("pagesize",page.getPageSize());
        }

        // 新增排序
        if (entityClass.isAnnotationPresent(SortKey.class)){
            String value = this.entityClass.getAnnotation(SortKey.class).value();
            ucb = ucb.queryParam("sort", value);
        }

        URI uri = ucb.build().toUri();
        // 设置请求头，特别是Authorization头部来携带token
        HttpHeaders headers = new HttpHeaders();
        headers.add("Ds-Route-key", this.getDsRouteKey());
        // 不需要传递body对于GET请求来说，除非你需要传递JSON等格式的参数体，但通常不这么做。
        HttpEntity<String> entity = new HttpEntity<>(headers);
        // 执行GET请求并处理响应
        R response = restTemplate.exchange(uri, HttpMethod.GET, entity, R.class).getBody();
//        log.info("Response with params: {}",response.getData());
        PageUtils.clearPage();
        List<T> list = new ArrayList<>();
        if (R.isSuccess(response)) {
            Object data1 = response.getData();
            if (data1 != null) {
                JSONArray arrays = JSON.parseArray(JSON.toJSONString(data1));
                list = arrays.stream().map(o -> {
                    try {
                        return JSONObject.parseObject(JSONObject.toJSONString(o), this.getEntityClass());
                    } catch (Exception e) {
                        throw new RuntimeException(e);
                    }
                }).collect(Collectors.toList());
            }
        }
        return list;
    }

    @Override
    public TableDataInfo selectTListPage(T t) {

        PageUtils.startPage();

        List<T> list = this.selectTList(t);

        TableDataInfo rspData = new TableDataInfo();
        rspData.setCode(HttpStatus.SUCCESS);
        rspData.setList(list);
        rspData.setMsg("查询成功");
        // 总值
        rspData.setTotal(this.count(t));
        return rspData;
    }


    @Override
    public long count(T t) {
        RestTemplate restTemplate = new RestTemplate();
        Map<String, Object> map = DomainUtils.objectToMapForQuery(t);
        JSONObject jo = new JSONObject();
        if (!map.isEmpty()){
            if (map.size()>1){
                List list = new ArrayList();
                map.forEach((k,v)->{
                    JSONObject pa = new JSONObject();
                    pa.put(k,v);
                    list.add(pa);
                });
                jo.put("$and",list);
            }else {
                jo.putAll(map);
            }
        }
        UriComponentsBuilder ucb = UriComponentsBuilder.fromHttpUrl(geturl()+"/_size");
        if(!map.isEmpty()){
            ucb = ucb.queryParam("filter", jo.toJSONString());
        }
        URI uri = ucb.build().toUri();
        // 设置请求头，特别是Authorization头部来携带token
        HttpHeaders headers = new HttpHeaders();
        headers.add("Ds-Route-key", this.getDsRouteKey());
        // 不需要传递body对于GET请求来说，除非你需要传递JSON等格式的参数体，但通常不这么做。
        HttpEntity<String> entity = new HttpEntity<>(headers);
        // 执行GET请求并处理响应
        ResponseEntity<R> response = restTemplate.exchange(uri, HttpMethod.GET, entity, R.class);
        log.info("Response with params: {}",response.getBody().getData());
        if (R.isSuccess(response.getBody())) {
            JSONObject data = JSONObject.from(response.getBody().getData());
            return data.getLongValue("_size");
        }
        return 0;
    }

    @Override
    public int insertT(T t) {
        RestTemplate restTemplate = new RestTemplate();
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_JSON);
        headers.add("Ds-Route-key", this.getDsRouteKey());
        Map<String, Object> map = DomainUtils.objectToMapWithSnakeCaseKeys(t);
        ValueFilter valueFilter = new ValueFilter() {
            @Override
            public Object process(Object object, String name, Object value) {
                // 检查字段类型是否为 Long
                if (value instanceof Double) {
                    // 将 Double 转换为 String
                    return value.toString();
                }
                return value;
            }
        };

        String s = JSON.toJSONString(map,new SerializeFilter[]{ valueFilter });
//        String s = JSON.toJSONString(map);
        System.out.println(s);
        HttpEntity<String> formEntity = new HttpEntity<>(s, headers);
        R request = restTemplate.postForObject(geturl()+"?pk=" + getClassKey(), formEntity, R.class);
        log.info("{}",request);
        JSONObject jo = JSONObject.from(request.getData());
        if (R.isSuccess(request) && jo.getIntValue("inserted")>0) {
            return 1;
        }
        return 0;
    }

    @Override
    public Integer saveBatch(Collection<T> entityList) {
        RestTemplate restTemplate = new RestTemplate();
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_JSON);
        headers.add("Ds-Route-key", this.getDsRouteKey());
        List<Map<String, Object>> list = new ArrayList<>();
        entityList.stream().forEach(orbitFileDataMsg->{
            list.add(DomainUtils.objectToMapWithSnakeCaseKeys(orbitFileDataMsg));
        });
        ValueFilter valueFilter = new ValueFilter() {
            @Override
            public Object process(Object object, String name, Object value) {
                // 检查字段类型是否为 Long
                if (value instanceof Double) {
                    // 将 Double 转换为 String
                    return value.toString();
                }
                return value;
            }
        };

        String s = JSON.toJSONString(list,valueFilter);
//        String s = JSON.toJSONString(list);
        System.out.println(s);
        HttpEntity<String> formEntity = new HttpEntity<>(s, headers);
        R request = restTemplate.postForObject(geturl()+"?pk=" + getClassKey(), formEntity, R.class);
        log.info("{}",request);
        JSONObject jo = JSONObject.from(request.getData());
        if (R.isSuccess(request) && jo.getIntValue("inserted")>0) {
            return 1;
        }
        return 0;
    }

    @Override
    public int updateT(T t) {
        RestTemplate restTemplate = new RestTemplate();
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_JSON);
        headers.add("Ds-Route-key", this.getDsRouteKey());
        Map<String, Object> map = DomainUtils.objectToMapWithSnakeCaseKeys(t);
        String classKey = getClassKey();
        Object id =  map.get(classKey);
        map.remove(classKey);

        ValueFilter valueFilter = new ValueFilter() {
            @Override
            public Object process(Object object, String name, Object value) {
                // 检查字段类型是否为 Long
                if (value instanceof Double) {
                    // 将 Double 转换为 String
                    return value.toString();
                }
                return value;
            }
        };

        String s = JSON.toJSONString(map,new SerializeFilter[]{ valueFilter });
//        System.out.println(s);
        HttpEntity<String> formEntity = new HttpEntity<>(s, headers);
        R request = restTemplate.exchange(geturl()+"/"+id+"?pk=" + classKey, HttpMethod.PUT,formEntity,R.class).getBody();

        log.info("{}",request.getData());
        JSONObject jo = JSONObject.from(request.getData());
        if (R.isSuccess(request) && jo.getIntValue("modified")>0) {
            return 1;
        }
        return 0;
    }

    @Override
    public int deleteTByIds(Long[] ids) {
        RestTemplate restTemplate = new RestTemplate();
        String filter = "{\""+getClassKey()+"\":{\"$in\":"+JSON.toJSONString(ids)+"}}";
        UriComponentsBuilder ucb = UriComponentsBuilder.fromHttpUrl(geturl()+"/*");
        ucb = ucb.queryParam("filter", JSONObject.parseObject(filter));
        URI uri = ucb.build().toUri();
        // 设置请求头，特别是Authorization头部来携带token
        HttpHeaders headers = new HttpHeaders();
        headers.add("Ds-Route-key", this.getDsRouteKey());
        // 不需要传递body对于GET请求来说，除非你需要传递JSON等格式的参数体，但通常不这么做。
        HttpEntity<String> httpEntity = new HttpEntity<>(headers);
        // 执行GET请求并处理响应
        R result = restTemplate.exchange(uri, HttpMethod.DELETE, httpEntity, R.class).getBody();
        JSONObject jo = JSONObject.from(result.getData());
        if (R.isSuccess(result)) {
            return jo.getIntValue("deleted");
        }
        return 0;
    }

    @Override
    public int deleteTList(T t){
        RestTemplate restTemplate = new RestTemplate();
        Map<String, Object> map = DomainUtils.objectToMapForQuery(t);
        JSONObject jo = new JSONObject();
        if (!map.isEmpty()){
            if (map.size()>1){
                List list = new ArrayList();
                map.forEach((k,v)->{
                    JSONObject pa = new JSONObject();
                    pa.put(k,v);
                    list.add(pa);
                });
                jo.put("$and",list);
            }else {
                jo.putAll(map);
            }
        }
        UriComponentsBuilder ucb = UriComponentsBuilder.fromHttpUrl(geturl());
        if(!map.isEmpty()){
            ucb = ucb.queryParam("filter", jo.toJSONString());
        }
        URI uri = ucb.build().toUri();

        // 设置请求头，特别是Authorization头部来携带token
        HttpHeaders headers = new HttpHeaders();
        headers.add("Ds-Route-key", this.getDsRouteKey());
        // 不需要传递body对于GET请求来说，除非你需要传递JSON等格式的参数体，但通常不这么做。
        HttpEntity<String> httpEntity = new HttpEntity<>(headers);
        // 执行GET请求并处理响应
        R result = restTemplate.exchange(uri, HttpMethod.DELETE, httpEntity, R.class).getBody();
        JSONObject jsonObject = JSONObject.from(result.getData());
        if (R.isSuccess(result)) {
            return jsonObject.getIntValue("deleted");
        }
        return 0;
    }

    @Override
    public int deleteTByIds(String[] ids) {
        RestTemplate restTemplate = new RestTemplate();
        String filter = "{\""+getClassKey()+"\":{\"$in\":"+JSON.toJSONString(ids)+"}}";
        UriComponentsBuilder ucb = UriComponentsBuilder.fromHttpUrl(geturl()+"/*");
        ucb = ucb.queryParam("filter", JSONObject.parseObject(filter));
        URI uri = ucb.build().toUri();
        // 设置请求头，特别是Authorization头部来携带token
        HttpHeaders headers = new HttpHeaders();
        headers.add("Ds-Route-key", this.getDsRouteKey());
        // 不需要传递body对于GET请求来说，除非你需要传递JSON等格式的参数体，但通常不这么做。
        HttpEntity<String> httpEntity = new HttpEntity<>(headers);
        // 执行GET请求并处理响应
        R result = restTemplate.exchange(uri, HttpMethod.DELETE, httpEntity, R.class).getBody();
        JSONObject jo = JSONObject.from(result.getData());
        if (R.isSuccess(result)) {
            return jo.getIntValue("deleted");
        }
        return 0;
    }

    @Override
    public int deleteTById(Long id) {
        RestTemplate restTemplate = new RestTemplate();
//        restTemplate.delete(geturl()+"/"+id+"?pk=" + getClassKey(), String.class);
        UriComponentsBuilder ucb = UriComponentsBuilder.fromHttpUrl(geturl()+"/"+id);
        ucb = ucb.queryParam("pk", getClassKey());
        URI uri = ucb.build().toUri();
        // 设置请求头，特别是Authorization头部来携带token
        HttpHeaders headers = new HttpHeaders();
        headers.add("Ds-Route-key", this.getDsRouteKey());
        // 不需要传递body对于GET请求来说，除非你需要传递JSON等格式的参数体，但通常不这么做。
        HttpEntity<String> httpEntity = new HttpEntity<>(headers);
        // 执行GET请求并处理响应
        R result = restTemplate.exchange(uri, HttpMethod.DELETE, httpEntity, R.class).getBody();
        return 1;
    }

    @Override
    public int deleteTById(String id) {
        RestTemplate restTemplate = new RestTemplate();
        UriComponentsBuilder ucb = UriComponentsBuilder.fromHttpUrl(geturl()+"/"+id);
        ucb = ucb.queryParam("pk", getClassKey());
        URI uri = ucb.build().toUri();
        // 设置请求头，特别是Authorization头部来携带token
        HttpHeaders headers = new HttpHeaders();
        headers.add("Ds-Route-key", this.getDsRouteKey());
        // 不需要传递body对于GET请求来说，除非你需要传递JSON等格式的参数体，但通常不这么做。
        HttpEntity<String> httpEntity = new HttpEntity<>(headers);
        // 执行GET请求并处理响应
        R result = restTemplate.exchange(uri, HttpMethod.DELETE, httpEntity, R.class).getBody();
        return 1;
    }


    @Override
    public int deleteTableInfo() {
        RestTemplate restTemplate = new RestTemplate();
        //restTemplate.delete(geturl()+"/*?filter={filter}", "{\""+getClassKey()+"\":{}}");
        UriComponentsBuilder ucb = UriComponentsBuilder.fromHttpUrl(geturl()+"/*");
        ucb = ucb.queryParam("filter", "{\""+getClassKey()+"\":{}}");
        URI uri = ucb.build().toUri();
        // 设置请求头，特别是Authorization头部来携带token
        HttpHeaders headers = new HttpHeaders();
        headers.add("Ds-Route-key", this.getDsRouteKey());
        // 不需要传递body对于GET请求来说，除非你需要传递JSON等格式的参数体，但通常不这么做。
        HttpEntity<String> httpEntity = new HttpEntity<>(headers);
        // 执行GET请求并处理响应
        R result = restTemplate.exchange(uri, HttpMethod.DELETE, httpEntity, R.class).getBody();
        return 1;
    }

    /**
     * 获取对象主键
     * @return String
     * @Author 何广森
     * @Date   2025/5/29 19:31
     */

    private String getClassKey(){
        // 获取对象 遍历属性字段
        Field[] fields = this.getEntityClass().getDeclaredFields();

        for (Field field : fields) {
            field.setAccessible(true); // 确保可以访问私有字段

            // 查看是否有注解
            if (field.isAnnotationPresent(ClassKey.class)){
                // 获取字段名称 将名称改为 xx_xx
               return DomainUtils.camelCaseToUpperCaseUnderscore(field.getName());
            }
        }
        // 没有返回 ID
        return "ID";
    }



    @Override
    public List selectBySql(String sql) {
        return this.selectBySql(sql,entityClass);
    }


    @Override
    public List selectBySql(String sql,Class clazz) {
        RestTemplate restTemplate = new RestTemplate();
        UriComponentsBuilder ucb = UriComponentsBuilder.fromHttpUrl(getTableUrl() + "_search");
        URI uri = ucb.build().toUri();
        // 设置请求头，特别是Authorization头部来携带token
        HttpHeaders headers = new HttpHeaders();
        headers.add("Ds-Route-key", this.getDsRouteKey());
        headers.setContentType(MediaType.APPLICATION_JSON);

        // 构建请求体对象
        Map<String, String> requestBody = new HashMap<>();
        requestBody.put("sql", sql);

        String s = JSON.toJSONString(requestBody);

        HttpEntity<String> httpEntity = new HttpEntity<>(s,headers);
        // 执行GET请求并处理响应

        R result = restTemplate.exchange(uri, HttpMethod.POST, httpEntity, R.class).getBody();
        List list = new ArrayList<>();
        if (R.isSuccess(result)) {
            Object data1 = result.getData();
            if (data1 != null) {
                JSONArray arrays = JSON.parseArray(JSON.toJSONString(data1));
                list = arrays.stream().map(o -> {
                    try {
                        return JSONObject.parseObject(JSONObject.toJSONString(o), clazz);
                    } catch (Exception e) {
                        throw new RuntimeException(e);
                    }
                }).collect(Collectors.toList());
            }
        }
        return list;
    }


    @Override
    public R selectRBySql(String sql) {
        RestTemplate restTemplate = new RestTemplate();
        UriComponentsBuilder ucb = UriComponentsBuilder.fromHttpUrl(getTableUrl() + "_search");
        URI uri = ucb.build().toUri();
        // 设置请求头，特别是Authorization头部来携带token
        HttpHeaders headers = new HttpHeaders();
        headers.add("Ds-Route-key", this.getDsRouteKey());
        headers.setContentType(MediaType.APPLICATION_JSON);

        // 构建请求体对象
        Map<String, String> requestBody = new HashMap<>();
        requestBody.put("sql", sql);

        String s = JSON.toJSONString(requestBody);

        HttpEntity<String> httpEntity = new HttpEntity<>(s,headers);
        // 执行GET请求并处理响应

        return restTemplate.exchange(uri, HttpMethod.POST, httpEntity, R.class).getBody();
    }
}
